﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Microsoft.Win32;
using Microsoft.Windows.Controls.Ribbon;
using NET.Tools;
using Puzzler.GUI.Windows.Wizard;
using Puzzler.Plugin;
using Puzzler.Plugin.Interface;
using Puzzler.Project;
using Puzzler.Utils;
using PluginManager = Puzzler.Plugin.PluginManager;

namespace Puzzler.GUI
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : RibbonWindow
    {
        private IDictionary<Type, RibbonContextualTabGroup> contextualTabGroups = new Dictionary<Type, RibbonContextualTabGroup>();
        private IPuzzlePlugin currentInstance = null;

        public MainWindow()
        {
            InitializeComponent();

            //Create a contextual group for each plugin
            foreach (PluginObject pluginObject in PluginManager.Instance.AllPuzzles)
            {
                RibbonContextualTabGroup tabGroup = new RibbonContextualTabGroup
                    {
                        Header = pluginObject.PuzzleInfo.Name,
                        Background = Ribbon.PressedBackground
                    };
                Ribbon.ContextualTabGroups.Add(tabGroup);
                contextualTabGroups.Add(pluginObject.PuzzleClass, tabGroup);

                RibbonBuilder.ExtendRibbon(Ribbon, pluginObject.RibbonExtension, pluginObject.PuzzleInfo.Name,
                    new RibbonDelegates(RibbonButtonAction, RibbonCheckedAction, RibbonUncheckedAction, RibbonSelectedAction, RibbonUnselectedAction));
            }
        }

        #region Ribbon Action Handler

        private void RibbonButtonAction(String key)
        {
            if (currentInstance == null)
                return;

            currentInstance.OnRibbonButtonClick(key);
        }

        private void RibbonCheckedAction(String key)
        {
            if (currentInstance == null)
                return;

            currentInstance.OnRibbonChecked(key);
        }

        private void RibbonUncheckedAction(String key)
        {
            if (currentInstance == null)
                return;

            currentInstance.OnRibbonUnchecked(key);
        }

        private void RibbonSelectedAction(String key)
        {
            if (currentInstance == null)
                return;

            currentInstance.OnRibbonSelected(key);
        }

        private void RibbonUnselectedAction(String key)
        {
            if (currentInstance == null)
                return;

            currentInstance.OnRibbonUnselected(key);
        }

        #endregion

        private void tvPuzzle_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            //Cleanup canvas
            canvas.Children.Clear();
            //Cleanup contextual tab groups on ribbon
            foreach (RibbonContextualTabGroup tabGroup in contextualTabGroups.Values)
            {
                tabGroup.Visibility = Visibility.Hidden;
            }
            //Remove canvas from renderer
            if (currentInstance != null)
            {
                currentInstance.Canvas = null;
            }

            //Check selected item and handle
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                //Redraw new selected puzzle
                puzzlePlugin.DrawEditorView(canvas);
                //Refresh contextual tab group on ribbon
                if (!contextualTabGroups.ContainsKey(puzzlePlugin.GetType()))
                    throw new Exception("Program-Logic-Error!");
                contextualTabGroups[puzzlePlugin.GetType()].Visibility = Visibility.Visible;
                //Setup current plugin instance
                currentInstance = puzzlePlugin;
                //Update renderer canvas
                currentInstance.Canvas = canvas;
            }
            else
            {
                currentInstance = null;
            }
        }

        #region Input

        #region Mouse Input

        private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                puzzlePlugin.OnLeftMouseButtonDown(e.GetPosition(canvas), e);
            }
        }

        private void canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                puzzlePlugin.OnLeftMouseButtonUp(e.GetPosition(canvas), e);
            }
        }

        private void canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                puzzlePlugin.OnMouseMove(e.GetPosition(canvas), e);
            }
        }

        private void canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                puzzlePlugin.OnRightMouseButtonDown(e.GetPosition(canvas), e);
            }
        }

        private void canvas_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                puzzlePlugin.OnRightMouseButtonUp(e.GetPosition(canvas), e);
            }
        }

        private void canvas_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                puzzlePlugin.OnMouseWheel(e.GetPosition(canvas), e);
            }
        }

        #endregion

        #region Key Input

        private void RibbonWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                puzzlePlugin.OnKeyDown(e);
            }
        }

        private void RibbonWindow_KeyUp(object sender, KeyEventArgs e)
        {
            if (tvPuzzle.SelectedItem is IPuzzlePlugin)
            {
                var puzzlePlugin = (tvPuzzle.SelectedItem as IPuzzlePlugin);
                puzzlePlugin.OnKeyUp(e);
            }
        }

        #endregion

        #endregion

        private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (PuzzlerProjectService.ProjectInfo == null)
            {
                SaveAs_Executed(sender, e);
            }
            else
            {
                PuzzlerProjectService.Save();
            }
        }

        private void SaveAs_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            SaveFileDialog dlg = DialogUtils.CreateFileDialog<SaveFileDialog>();

            if (dlg.ShowDialog().GetValueOrDefault(false))
            {
                String fileName = dlg.FileName;
                FileType fileType = FileTypeUtils.FromExt(dlg.FileName);

                PuzzlerProjectService.SaveAs(fileName, fileType);
            }
        }

        private void Load_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            OpenFileDialog dlg = DialogUtils.CreateFileDialog<OpenFileDialog>();

            if (dlg.ShowDialog().GetValueOrDefault(false))
            {
                String fileName = dlg.FileName;
                FileType fileType = FileTypeUtils.FromExt(dlg.FileName);

                PuzzlerProjectService.Reset();
                PuzzlerProjectService.Load(fileName, fileType);
            }
        }

        private void New_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            PuzzlerProjectService.Reset();
        }

    }
}
